package cn.ewan.cloud.tenant.data.router.redis.component;

import cn.ewan.cloud.common.support.Log;
import cn.ewan.cloud.common.support.utils.TraceUtil;
import cn.ewan.cloud.tenant.data.router.core.business.context.TenantContext;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.RedisConnectionFailureException;
import org.springframework.data.redis.connection.*;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;

import java.util.Map;

/**
 * @author lgh
 * @date 2023/3/3 10:41
 */
public class MultiRedisFactory implements InitializingBean, DisposableBean, RedisConnectionFactory, ReactiveRedisConnectionFactory {

    private final Map<String, LettuceConnectionFactory> factoryMap;


    public MultiRedisFactory(Map<String, LettuceConnectionFactory> factoryMap) {
        this.factoryMap = factoryMap;
    }


    @Override
    public void destroy() {
        factoryMap.values().forEach(LettuceConnectionFactory::destroy);
    }


    @Override
    public void afterPropertiesSet() {
        factoryMap.values().forEach(LettuceConnectionFactory::afterPropertiesSet);
    }


    private LettuceConnectionFactory getMultiFactory() {
        String tenant = TenantContext.getTenant();
        if (!factoryMap.containsKey(tenant)) {
            throw new RedisConnectionFailureException("invalid key: " + tenant + ", it does not exists in configuration");
        }
        LettuceConnectionFactory factory = factoryMap.get(tenant);
        Log.NORMAL.debug("get redis factory, threadId={}, traceId={}, tenant={}, redis-hostname={}, redis-port={}, factoryMapKeys={}",
                Thread.currentThread().getId(), TraceUtil.getTraceId(), tenant, factory.getHostName(), factory.getPort(), factoryMap.keySet());
        return factory;
    }


    @Override
    public ReactiveRedisConnection getReactiveConnection() {
        Log.NORMAL.debug("get redis factory, getReactiveConnection");
        return getMultiFactory().getReactiveConnection();
    }


    @Override
    public ReactiveRedisClusterConnection getReactiveClusterConnection() {
        Log.NORMAL.debug("get redis factory, getReactiveClusterConnection");
        return getMultiFactory().getReactiveClusterConnection();
    }


    @Override
    public RedisConnection getConnection() {
        Log.NORMAL.debug("get redis factory, getConnection");
        return getMultiFactory().getConnection();
    }


    @Override
    public RedisClusterConnection getClusterConnection() {
        Log.NORMAL.debug("get redis factory, getClusterConnection");
        return getMultiFactory().getClusterConnection();
    }


    @Override
    public boolean getConvertPipelineAndTxResults() {
        Log.NORMAL.debug("get redis factory, getConvertPipelineAndTxResults");
        return getMultiFactory().getConvertPipelineAndTxResults();
    }

    @Override
    public RedisSentinelConnection getSentinelConnection() {
        Log.NORMAL.debug("get redis factory, getSentinelConnection");
        return getMultiFactory().getSentinelConnection();
    }


    @Override
    public DataAccessException translateExceptionIfPossible(RuntimeException ex) {
        Log.NORMAL.debug("get redis factory, translateExceptionIfPossible");
        return getMultiFactory().translateExceptionIfPossible(ex);
    }
}
